/*
 * Copyright (C) 2010 Tetsuya Yasuda <tetsuyayasuda@gmail.com>
 */
package jp.tyas.libs.lisp;

import java.io.PrintStream;
import java.io.Reader;

public class Toplevel extends SymbolContext
{
    Reader in;
    PrintStream out;

    public Toplevel (Reader in, PrintStream out)
    {
        super (new Builtin (in, out));

        this.in = in;
        this.out = out;

        set(new Symbol("*TOPLEVEL*", this, null));
    }

    public Object eval (Object sexp)
    {
        return Builtin.eval (sexp, this);
    }

    public Object read ()
    {
        return Builtin.read (in, this);
    }

    public void println (Object o)
    {
        Builtin.println (o, out);
    }

    public Context getToplevel ()
    {
        return this;
    }

    public void repl ()
    {
        while (true) {
            Object sexp;

            out.print ("# ");

            try {
                sexp = read ();
                println (sexp);

                sexp = eval (sexp);
                println (sexp);
            } catch (Exception e) {
                if ("EOF".equals (e.getMessage()))
                    break;
                e.printStackTrace (Builtin.getStdout(this));
            }
        }
    }

    static class TelnetClient extends Thread {
        java.net.Socket sock;
        Object obj;
        public TelnetClient (java.net.Socket sock, Object obj) {
            super();
            this.sock = sock;
            this.obj = obj;
        }
        public void run () {
            try {
                Toplevel lisp = new Toplevel
                    (new java.io.InputStreamReader(sock.getInputStream()),
                     new PrintStream(sock.getOutputStream()));
                lisp.set (new Symbol("*PRIV*", obj, null));
                lisp.repl();
            } catch (Exception e) {}
        }
    }

    public static void telnetd(int port, PrintStream out, Object obj) {
        try {
            java.net.ServerSocket serv = new java.net.ServerSocket(port);
            out.println (serv.toString());
            while (true) {
                java.net.Socket cli = serv.accept();
                out.println("accept " + cli.toString());
                new TelnetClient(cli, obj).start();
            }
        } catch (Exception e) {
            e.printStackTrace(out);
        }
    }

    public static void main (String[] args)
    {
        Toplevel lisp = new Toplevel (new java.io.InputStreamReader(System.in), System.out);

        try {
            long save = System.currentTimeMillis();
            
            for (int i = 0; i < args.length; i++) {
                lisp.out.print ("load file " + args[i] + "...");
                lisp.println (Builtin.load (new java.io.FileReader(args[i]), lisp));
            }

            lisp.out.println ("load time..." + (System.currentTimeMillis() - save) + " ms");
        } catch (java.io.FileNotFoundException e) {
          e.printStackTrace (Builtin.getStdout(lisp));
        }

        lisp.repl();
    }
}
